﻿// ************************************************************************************************
//
//  BingProbe
//
//  Simple web server probe to find all domains tied to an IP.
//  
//  NOTE: Thanks to fellow Microsoft Security MVP Obiwan for the idea to use Bing API in this way
//
//  Author: Dana Epp (dana@vulscan.com)
//  Copyright: 
// ************************************************************************************************
using System;
using System.Text.RegularExpressions;
using System.Net;
using ProbeWebServer.BingAPI;
using System.Xml;
using System.Collections;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace ProbeWebServer
{
    class BingProbe
    {
        // NOTE: You must get your own API key from Microsoft at http://www.bing.com/developers/createapp.aspx
        private static string AppID = "7798127B02DA23455A71FB5165FEA82108B69EDB";
        private static string BingEndPoint = "http://api.bing.net:80/soap.asmx";

        Hashtable siteCollection;
        BingPortTypeClient bing = null;

        public BingProbe()
        {
            siteCollection = new Hashtable();
            bing = new BingPortTypeClient(
                new BasicHttpBinding(), new EndpointAddress(BingEndPoint));
        }

        public void ListSites(string ipAddr)
        {
            IPAddress[] addrs = Dns.GetHostAddresses(ipAddr);

            foreach (IPAddress addr in addrs)
            {
                Console.WriteLine("\nAddress = {0}", addr);
                uint offSet = 0;
                SearchResponse response = ProbeServer(addr.ToString(), offSet);
                while (offSet < response.Web.Total)
                {
                    // Display the Web results.
                    foreach (WebResult result in response.Web.Results)
                    {
                        string[] splitURL = result.DisplayUrl.Split('/');

                        SiteInfo info = new SiteInfo();
                        info.Title = result.Title;
                        info.Description = result.Description;
                        info.DisplayURL = splitURL[0].ToLower();

                        if (!siteCollection.ContainsKey(info.DisplayURL))
                        {
                            siteCollection.Add(info.DisplayURL, info);
                        }
                    }

                    offSet += 50;
                    response = ProbeServer(addr.ToString(), offSet);
                }

                ShowSites();
            }
        }

        #region ProbeServer()
        SearchResponse ProbeServer(string ipAddr, uint offSet)
        {
            return bing.Search(BuildProbeRequest(ipAddr, offSet));
        }
        #endregion

        #region IsDottedDecimalIP()
        bool IsDottedDecimalIP(string possibleIP) 
        {
            bool ret = false;
            IPAddress testIP;
            Regex ipRegEx = new Regex(@"\b(?:\d{1,3}\.){3}\d{1,3}\b");

            if( ipRegEx.IsMatch(possibleIP) )
            {
                try
                {
                    ret = IPAddress.TryParse(possibleIP, out testIP); 
                }
                catch
                {
                    ret = false;
                }
            }

            return ret;
        }
        #endregion

        #region BuildProbeRequest()
        private SearchRequest BuildProbeRequest(string ipAddr, uint offSet)
        {
            BingAPI.SearchRequest request = new BingAPI.SearchRequest();

            // Common request fields (required)
            request.AppId = AppID;
            request.Query = "ip:" + ipAddr;
            request.Sources = new SourceType[] { SourceType.Web };

            // Common request fields (optional)
            request.Version = "2.0";
            request.Market = "en-us";
            request.Adult = AdultOption.Off;
            request.AdultSpecified = true;
            request.Options = new SearchOption[]
            {
                SearchOption.EnableHighlighting
            };

            request.Web = new BingAPI.WebRequest();
            request.Web.Count = 50;
            request.Web.CountSpecified = true;
            request.Web.Offset = offSet;
            request.Web.OffsetSpecified = true;
            request.Web.Options = new WebSearchOption[]
            {
                WebSearchOption.DisableQueryAlterations
            };

            return request;
        }
        #endregion

        #region DisplayErrors()
        void DisplayErrors(XmlNode errorDetails)
        {
            // Add the default namespace to the namespace manager.
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(
                errorDetails.OwnerDocument.NameTable);
            
            nsmgr.AddNamespace(
                "api",
                "http://schemas.microsoft.com/LiveSearch/2008/03/Search");

            XmlNodeList errors = errorDetails.SelectNodes(
                "./api:Errors/api:Error",
                nsmgr);

            if (errors != null)
            {
                // Iterate over the list of errors and display error details.
                Console.WriteLine("Errors:");
                Console.WriteLine();
                foreach (XmlNode error in errors)
                {
                    foreach (XmlNode detail in error.ChildNodes)
                    {
                        Console.WriteLine(detail.Name + ": " + detail.InnerText);
                    }

                    Console.WriteLine();
                }
            }
        }
        #endregion

        #region ShowSites()
        private void ShowSites()
        {
            foreach (SiteInfo info in siteCollection.Values)
            {
                Console.WriteLine(" " + info.DisplayURL);
            }
        }
        #endregion


    }

    public class SiteInfo
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string DisplayURL { get; set; }
    }
}
